package com.example.auth.demo.config;

import com.example.auth.demo.domain.auth.UserDetail;
import com.example.auth.demo.utils.JwtUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT认证过滤器，用于从HTTP请求中提取JWT令牌并进行验证
 * 继承OncePerRequestFilter确保在一次请求中只执行一次过滤逻辑
 * 此过滤器会在Spring Security的过滤器链中验证JWT令牌的有效性
 * 并将认证信息设置到SecurityContext中，以便后续授权使用
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.header}")
    private String token_header;

    @Resource
    private JwtUtils jwtUtils;

    /**
     * 处理HTTP请求的过滤逻辑，验证JWT令牌并设置认证信息
     *
     * @param request HTTP请求对象
     * @param response HTTP响应对象
     * @param chain 过滤器链，用于调用下一个过滤器
     * @throws ServletException 处理请求时可能发生的Servlet异常
     * @throws IOException 处理请求时可能发生的IO异常
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 从请求头中获取JWT令牌
        String auth_token = request.getHeader(this.token_header);
        final String auth_token_start = "Bearer ";

        // 验证令牌格式是否符合Bearer Token规范
        if (StringUtils.isNotEmpty(auth_token) && auth_token.startsWith(auth_token_start)) {
            // 提取实际的JWT令牌（去除"Bearer "前缀）
            auth_token = auth_token.substring(auth_token_start.length());
        } else {
            // 不按规范,不允许通过验证
            auth_token = null;
        }

        // 从JWT令牌中解析用户名
        String username = jwtUtils.getUsernameFromToken(auth_token);

        // 记录日志，便于调试和审计
        logger.info(String.format("Checking authentication for userDetail %s.", username));

        // 验证令牌是否存在、用户名是否有效以及SecurityContext中是否已存在认证信息
        if (jwtUtils.containToken(username, auth_token) && username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            // 从令牌中获取用户详细信息
            UserDetail userDetail = jwtUtils.getUserFromToken(auth_token);

            // 验证令牌是否有效（未过期、签名正确等）
            if (jwtUtils.validateToken(auth_token, userDetail)) {
                // 创建认证令牌，包含用户信息和权限
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
                // 设置认证详细信息（如IP地址、sessionId等）
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                // 记录认证成功日志
                logger.info(String.format("Authenticated userDetail %s, setting security context", username));
                // 将认证信息设置到SecurityContext中，供后续授权使用
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }

        // 继续执行过滤器链
        chain.doFilter(request, response);
    }
}